package com.gokzzz.quartz;

import com.gokzzz.entity.SysQuartzJob;
import com.gokzzz.exception.RunException;
import lombok.extern.slf4j.Slf4j;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;

import static org.quartz.TriggerBuilder.newTrigger;

/**
 * @author ganfujia
 * @date 2022/4/21 11:16
 */
@Slf4j
@Component
public class QuartzManage {

    private static final String JOB_NAME = "TASK_";

    @Resource
    private Scheduler scheduler;

    /**
     * 创建定时任务
     *
     * @param sysQuartzJob 定时任务
     */
    public void createScheduler(SysQuartzJob sysQuartzJob) {
        try {
            // 构建job信息
            JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class)
                    .withIdentity(JOB_NAME + sysQuartzJob.getId()).build();
            jobDetail.getJobDataMap().put(SysQuartzJob.JOB_KEY, sysQuartzJob);
            // 创建触发器
            Trigger trigger = newTrigger()
                    .withIdentity(JOB_NAME + sysQuartzJob.getId())
                    .forJob(jobDetail)
                    .withSchedule(CronScheduleBuilder.cronSchedule(sysQuartzJob.getCronExpression()))
                    .build();
            // 调度执行
            scheduler.scheduleJob(jobDetail, trigger);
            // 暂停任务
            if (Boolean.TRUE.equals(sysQuartzJob.getPause())) {
                pauseScheduler(sysQuartzJob);
            }
            log.info("任务名称:{},定时任务创建成功", sysQuartzJob.getJobName());
        } catch (Exception e) {
            log.error("创建定时任务失败", e);
            throw new RunException("创建定时任务失败");
        }
    }

    /**
     * 更新job cron表达式
     *
     * @param sysQuartzJob 定时任务
     */
    public void updateJobCron(SysQuartzJob sysQuartzJob) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + sysQuartzJob.getId());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            if (trigger != null) {
                trigger = trigger.getTriggerBuilder()
                        .withIdentity(triggerKey)
                        .withSchedule(CronScheduleBuilder.cronSchedule(sysQuartzJob.getCronExpression()))
                        .build();
                //重置启动时间
                ((CronTriggerImpl) trigger).setStartTime(new Date());
                trigger.getJobDataMap().put(SysQuartzJob.JOB_KEY, sysQuartzJob);

                scheduler.rescheduleJob(triggerKey, trigger);
                // 暂停任务
                if (Boolean.TRUE.equals(sysQuartzJob.getPause())) {
                    pauseScheduler(sysQuartzJob);
                }
                log.info("任务名称:{},定时任务更新成功", sysQuartzJob.getJobName());
            }
        } catch (Exception e) {
            log.error("更新定时任务失败", e);
            throw new RunException("更新定时任务失败");
        }

    }

    /**
     * 删除定时任务
     *
     * @param sysQuartzJob 定时任务
     */
    public void deleteScheduler(SysQuartzJob sysQuartzJob) {
        try {
            JobKey jobKey = JobKey.jobKey(JOB_NAME + sysQuartzJob.getId());
            if (scheduler.checkExists(jobKey)) {
                scheduler.pauseJob(jobKey);
                scheduler.deleteJob(jobKey);
                log.info("任务名称:{},定时任务删除成功", sysQuartzJob.getJobName());
            }
        } catch (Exception e) {
            log.error("删除定时任务失败", e);
            throw new RunException("删除定时任务失败");
        }
    }

    /**
     * 立即执行定时任务
     *
     * @param sysQuartzJob 定时任务
     */
    public void runScheduler(SysQuartzJob sysQuartzJob) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + sysQuartzJob.getId());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 如果不存在则创建一个定时任务
            if (trigger == null) {
                createScheduler(sysQuartzJob);
            }
            JobDataMap jobDataMap = new JobDataMap();
            jobDataMap.put(SysQuartzJob.JOB_KEY, sysQuartzJob);
            JobKey jobKey = JobKey.jobKey(JOB_NAME + sysQuartzJob.getId());
            scheduler.triggerJob(jobKey, jobDataMap);
            log.info("任务名称:{},定时任务立即执行成功", sysQuartzJob.getJobName());
        } catch (Exception e) {
            log.error("立即执行定时任务失败", e);
            throw new RunException("立即执行定时任务失败");
        }
    }

    /**
     * 暂停定时任务
     *
     * @param sysQuartzJob 定时任务
     */
    public void pauseScheduler(SysQuartzJob sysQuartzJob) {
        try {
            JobKey jobKey = JobKey.jobKey(JOB_NAME + sysQuartzJob.getId());
            if (scheduler.checkExists(jobKey)) {
                scheduler.pauseJob(jobKey);
                log.info("任务名称:{},定时任务暂停成功", sysQuartzJob.getJobName());
            }
        } catch (Exception e) {
            log.error("定时任务暂停失败", e);
            throw new RunException("定时任务暂停失败");
        }
    }

    /**
     * 恢复定时任务
     *
     * @param sysQuartzJob 定时任务
     */
    public void resumeScheduler(SysQuartzJob sysQuartzJob) {
        try {
            JobKey jobKey = JobKey.jobKey(JOB_NAME + sysQuartzJob.getId());
            if (scheduler.checkExists(jobKey)) {
                scheduler.resumeJob(jobKey);
                log.info("任务名称:{},定时任务恢复成功", sysQuartzJob.getJobName());
            }
        } catch (Exception e) {
            log.error("定时任务恢复失败", e);
            throw new RunException("定时任务恢复失败");
        }
    }


}
